package com.xinyin.aiqinhaiback.modbus;

import com.digitalpetri.modbus.FunctionCode;
import com.digitalpetri.modbus.codec.Modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.master.ModbusTcpMasterConfig;
import com.digitalpetri.modbus.requests.*;
import com.digitalpetri.modbus.responses.*;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class SimpleMasterExample {
    private ModbusTcpMaster master;
    private String ip;

    public SimpleMasterExample(String ip) {
        this.ip=ip;
        initModbusTcpMaster(ip);
    }

    /**
     * 获取TCP协议的Master
     *
     * @return
     */
    public  void initModbusTcpMaster(String ip) {
        if (master == null) {
            // 创建配置
            ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(ip).setPort(10038).build();
            master = new ModbusTcpMaster(config);
        }
    }

    /***
     * 释放资源
     */
    public  void release() {
        if (master != null) {
            master.disconnect();
        }
        Modbus.releaseSharedResources();
    }

    /**
     * 读取Coils开关量
     *
     * @param address
     *            寄存器开始地址
     * @param quantity
     *            数量
     * @param unitId
     *            ID
     * @return 读取值
     * @throws InterruptedException
     *             异常
     * @throws ExecutionException
     *             异常
     */
    public  Boolean readCoils(int address, int quantity, int unitId)
            throws InterruptedException, ExecutionException {
        Boolean result = null;
        CompletableFuture<ReadCoilsResponse> future = master.sendRequest(new ReadCoilsRequest(address, quantity),
                unitId);
        ReadCoilsResponse readCoilsResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
        if (readCoilsResponse != null) {
            ByteBuf buf = readCoilsResponse.getCoilStatus();
            result = buf.readBoolean();
            ReferenceCountUtil.release(readCoilsResponse);
        }
        return result;
    }

    /**
     * 读取readDiscreteInputs开关量
     *
     * @param address
     *            寄存器开始地址
     * @param quantity
     *            数量
     * @param unitId
     *            ID
     * @return 读取值
     * @throws InterruptedException
     *             异常
     * @throws ExecutionException
     *             异常
     */
    public  Boolean readDiscreteInputs(int address, int quantity, int unitId)
            throws InterruptedException, ExecutionException {
        Boolean result = null;
        CompletableFuture<ReadDiscreteInputsResponse> future = master
                .sendRequest(new ReadDiscreteInputsRequest(address, quantity), unitId);
        ReadDiscreteInputsResponse discreteInputsResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
        if (discreteInputsResponse != null) {
            ByteBuf buf = discreteInputsResponse.getInputStatus();
            result = buf.readBoolean();
            ReferenceCountUtil.release(discreteInputsResponse);
        }
        return result;
    }

    /**
     * 读取HoldingRegister数据
     *
     * @param address
     *            寄存器地址
     * @param quantity
     *            寄存器数量
     * @param unitId
     *            id
     * @return 读取结果
     * @throws InterruptedException
     *             异常
     * @throws ExecutionException
     *             异常
     */
    public  Number readHoldingRegisters(int address, int quantity, int unitId)
            throws InterruptedException, ExecutionException {
        Number result = null;
        CompletableFuture<ReadHoldingRegistersResponse> future = this.master
                .sendRequest(new ReadHoldingRegistersRequest(address, quantity), unitId);
        ReadHoldingRegistersResponse readHoldingRegistersResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
        if (readHoldingRegistersResponse != null) {
            ByteBuf buf = readHoldingRegistersResponse.getRegisters();
            result = buf.readFloat();
            ReferenceCountUtil.release(readHoldingRegistersResponse);
        }
        return result;
    }

    /**
     * 读取InputRegisters模拟量数据
     *
     * @param address
     *            寄存器开始地址
     * @param quantity
     *            数量
     * @param unitId
     *            ID
     * @return 读取值
     * @throws InterruptedException
     *             异常
     * @throws ExecutionException
     *             异常
     */
    public  Number readInputRegisters(int address, int quantity, int unitId)
            throws InterruptedException, ExecutionException {
        Number result = null;
        CompletableFuture<ReadInputRegistersResponse> future = this.master
                .sendRequest(new ReadInputRegistersRequest(address, quantity), unitId);
        ReadInputRegistersResponse readInputRegistersResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
        if (readInputRegistersResponse != null) {
            ByteBuf buf = readInputRegistersResponse.getRegisters();
            result = buf.readDouble();
            ReferenceCountUtil.release(readInputRegistersResponse);
        }
        return result;
    }

    /**
     * 写 HoldingRegister 数据
     * @param address 寄存器地址
     * @param value 写入值
     * @param unitId id
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public  void writeSingleRegister (int address, int value, int unitId) throws ExecutionException, InterruptedException {
        Number result = null;
        CompletableFuture<WriteSingleRegisterResponse> future = this.master
                .sendRequest(new WriteSingleRegisterRequest(address, value), unitId);
        WriteSingleRegisterResponse modbusResponse = future.get();
        if (modbusResponse != null) {
//            int addressValue = modbusResponse.getAddress();
//            int responseValue = modbusResponse.getValue();
            FunctionCode functionCode = modbusResponse.getFunctionCode();
            int responseValue = modbusResponse.getValue();

            System.out.println("functionCode = " + functionCode + " value = " + responseValue);
//            System.out.println(addressValue);
//            System.out.println(responseValue);
        }

//        return result;
    }


//    public static void writeMultipleRegister (int address, int quantity, ByteBuf byteBuf, int unitId) throws ExecutionException, InterruptedException {
//        WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(address, quantity, byteBuf);
//        CompletableFuture<WriteMultipleRegistersResponse> future = master.sendRequest(request, unitId);
//        WriteMultipleRegistersResponse modbusResponse = future.get();
//        if (modbusResponse != null) {
//            int responseAddress = modbusResponse.getAddress();
//            int responseQuantity = modbusResponse.getQuantity();
//            FunctionCode functionCode = modbusResponse.getFunctionCode();
//            System.out.println("responseAddress = " + responseAddress);
//            System.out.println("responseQuantity = " + responseQuantity);
//            System.out.println("functionCode = " + functionCode);
//        }
//    }

    public  void writeMultipleRegisters(int slaveId, int address, int quantity, byte[] values) throws ExecutionException, InterruptedException {

        CompletableFuture<WriteMultipleRegistersResponse> futureResponse = this.master.sendRequest(new WriteMultipleRegistersRequest(address, quantity, values),
                slaveId);
        WriteMultipleRegistersResponse writeMultipleRegistersResponse = futureResponse.get();

//        return futureResponse.handle((response, ex) -> {
//            if (ex != null) {
//                ReferenceCountUtil.release(response);
//                return false;
//            } else {
//                int responseQuantity = response.getQuantity();
//                ReferenceCountUtil.release(response);
//                return values.length == responseQuantity;
//            }
//        });
    }


    public static byte[] intToByte(int[] values) {
        byte[] bytes = new byte[values.length * 2];
        for (int i = 0; i < bytes.length; i += 2) {
            bytes[i] = (byte) (values[i / 2] >> 8 & 0xFF);
            bytes[i + 1] = (byte) (values[i / 2] & 0xFF);
        }
        return bytes;
    }

    /// <summary>
    /// float[] 转 byte[]
    /// </summary>
    /// <param name="datas"></param>
    /// <returns></returns>
    public static byte[] floatArrayToByteArray(float[] floats) {
        ByteBuffer buffer = ByteBuffer.allocate(4 * floats.length);
        FloatBuffer floatBuffer = buffer.asFloatBuffer();
        floatBuffer.put(floats);

        return buffer.array();
    }


    /**
     * bytes 数组 转 float 数组
     * @param bytes
     * @return
     */
    public static float[] byteArrayToFloatArray(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        FloatBuffer fb = buffer.asFloatBuffer();
        float[] floatArray = new float[fb.limit()];
        fb.get(floatArray);
        return floatArray;
    }

//    public static void writeMultipleRegisters (int address, int quantity, int[] values, int unitId) {
//        byte[] bytes = intToByte(values);
//        WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(address, quantity, bytes);
//        CompletableFuture<WriteMultipleRegistersResponse> future = master.sendRequest(request, unitId);
//        future.handle((response, ex) -> {
//            if (ex != null) {
//                ReferenceCountUtil.release(response);
//                return false;
//            } else {
//                System.out.println(response.getQuantity());
//                int responseQuantity = response.getQuantity();
//                ReferenceCountUtil.release(response);
//                return values.length == responseQuantity;
//            }
//        });
//    }

    public static void main(String[] args) {
        try {

            SimpleMasterExample simpleMasterExample=new SimpleMasterExample("211.154.22.175");
            simpleMasterExample.initModbusTcpMaster("211.154.22.175");


            // 读取开关量
//            System.out.println("F == 01");
//            System.out.println(simpleMasterExample.readCoils(143, 1, 1));
//
//            System.out.println("F == 02");
//            System.out.println(readDiscreteInputs(631, 1, 1));
//            System.out.println(readDiscreteInputs(1, 1, 1));
//            System.out.println(readDiscreteInputs(2, 1, 1));
//
//
            // 读取模拟量
//            System.out.println("F == 03");
//
//            System.out.println(simpleMasterExample.readHoldingRegisters(3321, 2, 1).toString());
//            float c=Float.parseFloat(simpleMasterExample.readHoldingRegisters(3321, 2, 1).toString());
//            System.out.println(c);

//
            System.out.println("F == 04");
           System.out.println(simpleMasterExample.readInputRegisters(46, 15, 1));
           // float c=Float.parseFloat(simpleMasterExample.readInputRegisters(1, 2, 1).toString());
           // System.out.println(c);
//            System.out.println(readInputRegisters(6, 4, 1));
//            master.sendRequest(new WriteSingleRegisterRequest(0,0), 1);
//            writeSingleRegister(0,4,1);
//            float[] arr = new float[]{99f};
//            byte[] bytes = floatArrayToByteArray(arr);
//            simpleMasterExample.writeMultipleRegisters(1, 3, arr.length * 2, bytes);

            simpleMasterExample.release();
        } catch (Exception e) {
            System.out.println("异常");
            e.printStackTrace();
        }
    }

}
